const inquirer = require('inquirer')
const fs = require('fs')
const cmd = require('child_process')
const path = require('path')
const utils = require('./utils')
const ora = require('ora')
let loading = ora()

// child_process.exec 所需的参数，避免 maxBuffer 不足而导致错误
const execOption = {
        encoding: 'utf8',
        timeout: 0,
        maxBuffer: 1000 * 1024 * 1024, // 默认 200 * 1024
        killSignal: 'SIGTERM'
    }

/*
 * 编译项目，合并 framework，为公司项目定制
 *
 * 流程
 * - 编译 XYMainApp 下对应 Pods-target 模块
 * - 再编译对应的 target 项目
 * 
 * - 问题：目前编译账号等模块没问题，对于 EC 的拆分模块编译不通过
 */
async function wm_framework() {
    try {
        let startTime = new Date().getTime();

        let target = await getTarget()
        let answer = await initParam(target)

        let targetPath = process.cwd()
        let mainAppPath = path.resolve(process.cwd(), '../', answer.rootTarget)
        let podsProject = `${mainAppPath}/Pods/Pods.xcodeproj`
        let podsTarget = `Pods-${answer.target}`
        let targetProject = `${targetPath}/${answer.target}.xcodeproj`
        // 自定义 build 产物路径
        let customBuildDir = path.resolve(process.cwd(), '../DerivedData/Build')
        // 编译 pods
        await buildAction(podsProject, podsTarget, answer.configuration, 'iphonesimulator', customBuildDir)
        await buildAction(podsProject, podsTarget, answer.configuration, 'iphoneos', customBuildDir)
        // 编译 target
        await buildAction(targetProject, answer.target, answer.configuration, 'iphonesimulator', customBuildDir)
        await buildAction(targetProject, answer.target, answer.configuration, 'iphoneos', customBuildDir)

        // create output
        let outputFrameworkDir = answer.mergePath
        let iphoneosFrameworkDir = `${customBuildDir}/${answer.configuration}-iphoneos/${answer.target}.framework`
        await createOutputDir(outputFrameworkDir, iphoneosFrameworkDir)

        // merge
        let iphoneosFrameworkFilePath = `${iphoneosFrameworkDir}/${answer.target}`
        let simulatorFrameworkFilePath = `${customBuildDir}/${answer.configuration}-iphonesimulator/${answer.target}.framework/${answer.target}`
        let outputFrameworkFilePath = `${outputFrameworkDir}/${answer.target}.framework/${answer.target}`
        await mergeAction(iphoneosFrameworkFilePath, simulatorFrameworkFilePath, outputFrameworkFilePath)
        
        deleteUselessDir(mainAppPath)
        deleteUselessDir(targetPath)

        let endTime = new Date().getTime()
        utils.printLog(`总耗时：[${(endTime-startTime)/1000} sec]`)
    } catch (error) {
        console.log(error)
    }
}

/**
 * 1、从当前路径下读取基本信息，获取 target
 */
function getTarget() {
    return new Promise((resolve, reject) => {
        fs.readdir(process.cwd(), (err, files) => {
            if (err) {
                console.log(err)
                reject(err)
            }
            let target = null
            files.forEach(file => {
                if (file.includes('.xcworkspace')) {
                    target = file.split('.')[0]
                    return
                }
                if (file.includes('.xcodeproj')) {
                    target = file.split('.')[0]
                }
            })
            resolve(target)
        })
    })
}

function initParam(target) {
    const promptList = [
        {
            type: 'input',
            name: 'target',
            message: '项目 Target 名字？',
            default: target
        },
        {
            type: 'input',
            name: 'rootTarget',
            message: '主工程名字？',
            default: 'XYMainApp'
        },
        {
            type: 'list',
            name: 'configuration',
            message: '编译的环境?',
            choices: [
                'Debug',
                'Release'
            ]
        },
        {
            type: 'input',
            name: 'mergePath',
            message: '合并后 framework 存放路径？',
            default: './Framework'
        }
    ]
    return new Promise((resolve, reject) => {
        inquirer.prompt(promptList)
            .then(answer => {
                resolve(answer)
            })
    })
}

/*
 * 编译
 */
function buildAction(project, target, configuration, sdk, buildDir) {
    loading.text = `build ${target} ${sdk}...`
    loading.start()
    let build_cmd = `xcodebuild build -project ${project} -target ${target} ONLY_ACTIVE_ARCH=NO -configuration ${configuration} -sdk ${sdk} BUILD_DIR=${buildDir}`
    return new Promise((resolve, reject) => {
        cmd.exec(build_cmd, execOption, (err, stdout) => {
            loading.stop()
            if (err) {
                return reject(err)
            }
            utils.printSuccessLog(`build ${target} ${sdk} succeeded`)
            resolve()
        })
    })
}

/*
 * 创建合并后的 framework，并把真机的 framework 产物复制进去
 */
function createOutputDir(outputFrameworkDir, iphoneosFrameworkDir) {
    return new Promise((resolve, reject) => {
        let exist = fs.existsSync(outputFrameworkDir)
        if (!exist) {
            fs.mkdirSync(outputFrameworkDir, {recursive: true})
        }
        // 复制一份 framework 到 output 
        cmd.exec(`cp -r ${iphoneosFrameworkDir} ${outputFrameworkDir}`, (err) => {
            if (err) {
                return reject(err)
            }
            resolve()
        })
    })
}

/*
 * 合并 framework 
 * 
 * lipo -create 命令会在当前项目路径下，创建一个 build 文件夹，存在编译产物
 */
function mergeAction(iphoneosFrameworkFilePath, simulatorFrameworkFilePath, outputFrameworkFilePath) {
    loading.text = 'merge...'
    loading.start()
    // 合并命令
    let merge_cmd = `lipo -create ${iphoneosFrameworkFilePath} ${simulatorFrameworkFilePath} -output ${outputFrameworkFilePath}`
    // 合并产物会替换输出路径中存在的 framework 文件
    return new Promise((resolve, reject) => {
        cmd.exec(merge_cmd, execOption, (err, stdout) => {
            loading.stop()
            if (err) {
                return reject(err)
            }
            utils.printSuccessLog('merge succeeded')
            resolve()
        })
    })
}

/*
 * 删除操作过程中的产物
 *
 * - MainApp/build
 * - Target/build
 */
function deleteUselessDir(dir) {
    dir = `${dir}/build`
    cmd.execSync(`rm -r ${dir}`)
    utils.printSuccessLog(`delete ${dir} succeeded`)
}

module.exports = wm_framework;